#include "constants.h"

private ["_debug","_can_run","_player_number","_wait_time","_roadblocks","_roadblock","_units","_alive_units","_vec_types","_alive_vehicles"];
_debug = true;
_can_run = true;
_player_number = 0;
_wait_time = 1800;
// Contains a list of all roadblocks which have been spawn.
// One roadblock is described with: [Zone,SpawnTime,StartPos,ObjectName,[unit1,unit2,unit3,..]]
_roadblocks = [];
_sector_spawn_times = [];
_own_side = switch (d_own_side) do {case "EAST": {east};case "WEST": {west};case "GUER": {resistance};case "CIV": {civilian}; default{west};};

If (isNil "D_LAST_RANDOM_SPAWN_ID") then {D_LAST_RANDOM_SPAWN_ID = 1;};
D_LAST_RANDOM_SPAWN_ID = D_LAST_RANDOM_SPAWN_ID + 1;
_marker_id = D_LAST_RANDOM_SPAWN_ID;

				_spawn_sectors = [d_map_sectors,[XF_SECTOR_ARRAY_TYPE,"==",XF_SECTOR_TYPE_SPAWN]] call XfTableFilter;
				if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomroadblocks.sqf","Spawn Sectors",_spawn_sectors];};
				// Next we check which sectors are already active.
				_current_sectors = [];
				{	_sector = _x select XF_SPAWN_ARRAY_SECTOR;
					if !(_sector in _current_sectors) then {_current_sectors set [count _current_sectors, _sector];};
				} foreach _roadblocks;
				// If there are as many active sectors as possible sectors, we just pick one randomly.
				_sector = -1;
				if ((count _current_sectors) >= (count _spawn_sectors)) then {
					_sector = floor(random(count _spawn_sectors));
				} else {
					_select_sectors = [];
					for [{_i = 0},{_i < count _spawn_sectors},{_i = _i + 1}] do {
						if !(_i in _current_sectors) then {_select_sectors set [count _select_sectors, _i];};
					};
					_sector = _select_sectors call XfRandomArrayVal;
				};


						// Ok... now we can try to spawn a roadblock :-)
						_spawn_sector = _spawn_sectors select _sector;
						_shape_arrays = _spawn_sector select XF_SECTOR_ARRAY_SHAPE_ARRAY;
						if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomroadblocks.sqf","Sector Shapes",_shape_arrays];};
						_grp = objNull;
						_roadblock = [];
						_eligible_towns = [d_map_locations, [XF_MAP_LOCATION_TYPE,"IN",[XF_MAP_LOCATION_TYPE_TOWN,XF_MAP_LOCATION_TYPE_VILLAGE]]] call XfTableFilter;
						if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomroadblocks.sqf","Eligible Towns",_eligible_towns];};
						_towns = [];
						{
							_town = _x;
							_valid = false;
							{
								_valid = [(_town select XF_MAP_LOCATION_CENTER), _x] call XfPointInShape;
								if (_valid) exitWith {_towns set [ count _towns, _town ]; };
							}foreach _shape_arrays;
						} foreach _eligible_towns;
						if (count _towns > 0) then {
							// We randomize the result array
							_towns = _towns call XfRandomArray;
							sleep 1;
							// And again to ensure a better randomization (not that I don't trust "Random"...)
							_towns = _towns call XfRandomArray;
							if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomroadblocks.sqf","Towns",_towns];};
							_tries = 40;
							// Position, Slope, Units Density
							_best_spot = [[],2000,10000000,[]];
							_spot = [];
							_spot_dir = 0;
							_town_pos = [];
							_start_town = [];
							while {_tries > 0} do {
								_best_spot = [[],2000,10000000,[]];
								_town_pos = [];
								_spot = [];
								
								_start_town = _towns call XfRandomArrayVal;
								_tries2 = 20; // 10 tries per town
								_town_pos = (_start_town select XF_MAP_LOCATION_CENTER);
								_minimum_radius = (_start_town select XF_MAP_LOCATION_SIZE) + 60;
								_maximum_radius = (_start_town select XF_MAP_LOCATION_SIZE) + 250;
								While {(count _spot < 3) && _tries2 > 0} do {
									_spot = [_town_pos, _maximum_radius, _minimum_radius] call XfGetRanPointCircle;
									_roads = (_spot nearRoads 50);
									if (count _roads > 0) then {
										{
											// We check each roads to see it they fit the roadblock size (no obstacles).
											_road = _x;
											_nobs = (getPos _x) nearObjects 30;
											_obs_found = false;
											{
												if (_x isKindOf "Static") exitwith {_obs_found = true;};
												if (toArray(str(_x)) call XfIsTree) exitwith {_obs_found = true;};
											} foreach _nobs;
											if (!_obs_found) then { _spot = getPos _road };
										} foreach _roads;
									} else {
										_spot = [];
									};
									_tries2 = _tries2 - 1;
								};
								// We search a spot which has roads nearby
								if (count _spot == 3) then {
									if (_debug) then { diag_log Format["(%1)[%2]: %3: %4 %5",diag_tickTime,"randomroadblocks.sqf","Testing spot", _spot, _start_town]; };
									_lst = nearestObjects [_spot, ["Man","Car","Tank","Ship"], 400];
									_density = 0;
									{
										if ((side _x) == _own_side) then {
											if (_debug) then { diag_log Format["(%1)[%2]: %3: %4 (%5)",diag_tickTime,"randomroadblocks.sqf","Own Side", _x,(isplayer _x)]; };
											if (isplayer _x) then {
												// If a humen player is present, then we highly increase the density to reject as much as possible those spots
												_density = _density + (10000 / (_x distance _spot));
											} else {
												_density = _density + (2000 / (_x distance _spot));
											};
										};
									} foreach _lst;
									// We factor in the fact many units are present, to avoid spawning in an already crowded place
									_density = _density + (count _lst) * 25;
									_slope = [_spot, 20] call XfGetSlope;
									// 1) We test if the density is better or within range
									// 2) We test if the slope is either better... or within range of a good value
									if (((_density < (_best_spot select 2)) || (abs(_density - (_best_spot select 2)) < 100)) && ((_slope < (_best_spot select 1)) ||  ((abs(_slope - (_best_spot select 1))) < 5))) then {
										// We update the best spot
										_best_spot = [_spot, _slope, _density,_town_pos];
										// We lower the tries count to narrow a good spot more quickly
										_tries = _tries - 3;
										if (_debug) then { diag_log Format["(%1)[%2]: %3: %4 (%5)",diag_tickTime,"randomroadblocks.sqf","New best spot", _best_spot,_tries]; };
									};
								};
								_tries = _tries - 1;
								sleep 1.234;
							};
							if (_debug) then {diag_log ""; diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomroadblocks.sqf","Selected spot",_best_spot];};
							_spot = _best_spot select 0;
							_roadblock_1 = [];
							_roadblock_2 = [];
							If (count _spot == 3) then {
								_spot_dir = [_spot,(_best_spot select 3)] call XfDirTo;
								if (_debug) then { _markers set [count _markers, ([Format["mkr_tested_spot_%1",_marker_id],_spot, "ICON", "ColorRed", [0.7,0.7],"",_spot_dir,"x_mortar","",1] call XfCreateMarkerLocal)]; };
								// From here, we know approximatively where to start.
								// We have a road object with normally enough room around it for the road block.
								// Next step, finding the road items which are the most far from the original item.
								_roads = (_spot nearRoads 70);
								// if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomroadblocks.sqf","Roads",_roads]; [_roads, "   "] call XfArrayDump;};
								_extreme_roads = [];
								_extreme_roads_dir = [];
								_dist_town_best = 0;
								_road_town_best = -1;
								_best_extreme = [];
								if (count _roads > 0) then {
									// The following calculation will give the general direction of the road.
									// This will allow to place the roadblock on the side of this direction.
									// Plus, we will be able to orient the roadblock looking at the road in the direction going outside town.
									_i = 0;
									{
										_road = _x;
										_pos = getPos _road;
										_distance = (_pos distance _spot);
										_added = false;
										if ( _distance > 5) then {
											_dir = [_spot, _pos] call XfDirTo;
											// We check already existing dirs and if one is close, we merge them.
											_exist_dir = _dir;
											{
												_range_above = _x + 45;
												_range_below = _x - 45;
												if (_dir < _range_above && _dir > _range_below) exitWith{ _exist_dir = _x};
												// this handle the case of 350 and 0 being close to each other.
												if ((_dir - 360) < _range_above && (_dir - 360) > _range_below) exitWith{ _exist_dir = _x};
											}foreach _extreme_roads_dir;
											_idx = -1;
											if (_exist_dir in  _extreme_roads_dir) then {
												_idx = _extreme_roads_dir find _exist_dir;
												// We take the average, good for roads which are turning.
												_dir = (_exist_dir + _dir) / 2;
											} else {
												_idx =count _extreme_roads_dir;
											};
											// if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomroadblocks.sqf","Road",[_idx, _pos, _dir, _distance,((_best_spot select 3) distance (getPos _road))]];};
											if (_idx >=0) then {
												_extreme_roads_dir set [_idx, _dir];
												if (count _extreme_roads <= _idx) then {_extreme_roads set [_idx, _road]};
												_exist_road = (_extreme_roads select _idx);
												_exist_dist = _spot distance _exist_road;
												if (_exist_dist <= _distance) then {
													_added = true;
													_extreme_roads set [_idx, _road];
												};
												_dist_town = (_best_spot select 3) distance (getPos _road);
												if (_dist_town > _dist_town_best) then { _road_town_best = _idx;  _dist_town_best = _dist_town; _best_extreme = (getPos _road)};
											};
											if (_debug) then { 
												if (_added) then { _markers set [count _markers, ([format["mrk_road_%1_%2",_marker_id,_i],_pos, "ICON", "ColorRed", [0.6,0.6],Format["%1",_i],0,"mil_dot","",0.6] call XfCreateMarkerLocal)];
												} else {_markers set [count _markers, ([format["mrk_road_%1_%2",_marker_id,_i],_pos, "ICON", "ColorBlue", [0.6,0.6],Format["%1",_i],0,"mil_dot","",0.3] call XfCreateMarkerLocal)]; };
											};
										};
										_i = _i + 1;
									} foreach _roads;
									// Now we have a new array with the Extreme roads.
									// if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomroadblocks.sqf","Extreme Roads",_extreme_roads]; [_extreme_roads, "   "] call XfArrayDump;};
									// if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomroadblocks.sqf","Extreme Dirs",_extreme_roads_dir]; [_extreme_roads_dir, "   "] call XfArrayDump;};
									_median_extreme = [];
									if (count _extreme_roads > 0) then {
										for [{_i = 0},{_i < count _extreme_roads},{_i = _i + 1}] do {
											if (_debug) then {
												if (_i == _road_town_best) then { _markers set [count _markers, ([format["mrk_eroad_%1_%2",_marker_id,_i],(getPos (_extreme_roads select _i)), "ICON", "ColorGreen", [0.7,0.7],Format["%1",(_extreme_roads_dir select _i)],(_extreme_roads_dir select _i),"Arrow","",1] call XfCreateMarkerLocal)];
												} else { _markers set [count _markers, ([format["mrk_eroad_%1_%2",_marker_id,_i],(getPos (_extreme_roads select _i)), "ICON", "ColorBlack", [0.7,0.7],Format["%1",(_extreme_roads_dir select _i)],(_extreme_roads_dir select _i),"Arrow","",1] call XfCreateMarkerLocal)]; };
											};
											if (_i == 0) then {
												// We didn't set a value yet... so we start there.
												_median_extreme = (getPos (_extreme_roads select _i));
											} else {
												// We get the median point between both
												_mx = (((getPos (_extreme_roads select _i)) select 0) + (_median_extreme select 0)) / 2;
												_my = (((getPos (_extreme_roads select _i)) select 1) + (_median_extreme select 1)) / 2;
												_median_extreme = [_mx,_my,0];
											};
										};
										_spot = _median_extreme;
										_spot_dir = [_spot, _best_extreme] call XfDirTo;
										// From here we know approximatively where to build the road block.
										// We pickup the nearest road.
										_roads = (_spot nearRoads 20);
										_nearest_road=[0,0,0];
										{
											if ((_x distance _spot) < (_nearest_road distance _spot)) then {
												_nearest_road = getPos(_x);
												if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomroadblocks.sqf","Extreme Dirs",_extreme_roads_dir]; [_extreme_roads_dir, "   "] call XfArrayDump;};
											};
										}foreach _roads;
										if (count _roads == 0) then {_nearest_road = _spot};
										// Now we have it. We also know the direction to look to.
										if (_debug && ((_spot distance _nearest_road) > 0.5)) then {
											_veh = createVehicle ["MetalBucket", _nearest_road, [], 0, "CAN_COLLIDE"];
											_veh setPos _nearest_road;
										};
										// We take two spots outside of the road and spawn the roadblock on them
										_new_dir = _spot_dir + 90;
										_mx = (_nearest_road) select 0;
										_my = (_nearest_road) select 1;
										_mx = _mx + 5 * sin _new_dir;
										_my = _my + 5 * cos _new_dir;
										_roadblock_1 = [_mx,_my,0];	
										_new_dir = _spot_dir + 270;
										_mx = (_nearest_road) select 0;
										_my = (_nearest_road) select 1;
										_mx = _mx + 5 * sin _new_dir;
										_my = _my + 5 * cos _new_dir;
										_roadblock_2 = [_mx,_my,0];
									};
								} else {
									// No other roads... sounds impossible but whatever... let's spawn in place ;-)
								};
							};
							if ((count _roadblock_1) == 0) then {
								_roadblock_1 = _spot;
							};
							_units = [d_enemy_side_char,1,floor(random(5))] call XfMissionGetRandomFootmenUnits;
							_unit = [d_enemy_side_char,1,XF_VEHICLE_TYPES_LIGHTWHEEL] call XfMissionGetRandomVehicleUnits;
							_units = [_unit, _units] call XfArrayPushStack;
							if (count _units > 0) then {
								_nest = "";
								switch (d_enemy_side) do {
									case "WEST": {_units = [["USMC_WarfareBMGNest_M240"], _units] call XfArrayPushStack;};
									case "EAST": {_units = [["RU_WarfareBMGNest_PK"], _units] call XfArrayPushStack;};
									default {_units = [["GUE_WarfareBMGNest_PK"], _units] call XfArrayPushStack;};
								};
								if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"randomroadblocks.sqf","Units",_units];};
								
								_roadblock_units = [];
								_grp = [d_enemy_side] call x_creategroup;
								_grp setBehaviour "AWARE";
								_grp setFormation "LINE";
								_grp allowFleeing 0;
								_leader = objNull;
								_veh = objNull;
								If (count _roadblock_2 > 0) then {
									if (_debug) then { 
										_veh = createVehicle ["RoadCone", _spot, [], 0, "CAN_COLLIDE"];
										_veh setPos _spot;
									};
									_veh = createVehicle ["Land_fortified_nest_small", _roadblock_2, [], 0, "NONE"];
									_veh setDir (_spot_dir + 180);
									if (((vectorUp _veh) distance [0,0,1]) > 2) then { _veh setVectorUp [0,0,1];};
									_roadblock_units set [count _roadblock_units, _veh];
								};
								{
									if (_x isKindOf "Man") then {
										_veh = [_x, _grp, _spot, 10] call XfCreateUnit;
										// _veh = _grp createUnit [_x, _spot, [], 10, "NONE"];
									} else {
										_veh = createVehicle [_x, _spot, [], 10, "NONE"];
										if (((_veh isKindOf "Car") && (d_LockCars>0)) || ((_veh isKindOf "Tank") && (d_LockArmored>0)) || ((_veh isKindOf "Air") && (d_LockAir>0))) then {
											_veh lock true;
										};
									};
									_roadblock_units set [count _roadblock_units, _veh];
									// The special case of static weapons which received a precalculated position.
									if (_veh isKindOf "StaticWeapon") then {
										_veh setDir _spot_dir;
										_veh setPos _roadblock_1;
										if (((vectorUp _veh) distance [0,0,1]) > 2) then { _veh setVectorUp [0,0,1];};
									};
									if !(_veh isKindOf "Man") then {
										_crew = [_veh, _grp] call XfSpawnCrew;
										{ _roadblock_units set [count _roadblock_units, _x];
										} foreach crew _veh;
									};
									if (isNull _leader) then {
										_leader = leader _grp;
										_leader setRank "COLONEL";
									};
									sleep 1;
								} foreach _units;
								if (count _roadblock_units > 0) then {
									[_grp, _spot,false] spawn XfTaskDefend;
									_roadblock set [XF_SPAWN_ARRAY_SECTOR,_sector];
									_roadblock set [XF_SPAWN_ARRAY_SPAWNTIME,Time];
									_roadblock set [XF_SPAWN_ARRAY_STARTPOS,_spot];
									_roadblock set [XF_SPAWN_ARRAY_OBJECTNAME,Format["ROADBLOCK%1",_marker_id]];
									_roadblock set [XF_SPAWN_ARRAY_RADIUS,0];
									_roadblock set [XF_SPAWN_ARRAY_GROUP,_grp];
									_roadblock set [XF_SPAWN_ARRAY_UNITSARRAY,_roadblock_units];
									_markers set [count _markers, ([(_roadblock select XF_SPAWN_ARRAY_OBJECTNAME),_spot, "ICON", "ColorRed", [0.9,0.9],Format["%1 %2",(_roadblock select XF_SPAWN_ARRAY_OBJECTNAME),_spot_dir],_spot_dir,"mil_arrow2","",0.2] call XfCreateMarkerLocal)];
									_roadblock set [XF_SPAWN_ARRAY_MARKERSARRAY,_markers];
								};
							};
							"RoadBlock Done" call XfMissionMessageToAll;
						} else {
							// no towns found
							"RoadBlock No Town" call XfMissionMessageToAll;
						};
